package com.loong.android.viewpager;

import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;

import loong.lang.Array;

/**
 * 滑动页面(ViewPager)的基础适配器
 */
public class PagerBaseAdapter<T> extends PagerAdapter {

    protected Event<T> event;
    protected Array<T> itemDataList;
    protected Object extra;

    /**
     * 取列表项目数据集合
     */
    public Array<T> getItemDataList() {
        return itemDataList;
    }

    /**
     * 设置页面项目的数据集合
     *
     * @param itemDataList 数组集合
     */
    public PagerBaseAdapter<T> setItemDataList(Array<T> itemDataList) {
        this.itemDataList = itemDataList;
        return this;
    }

    /**
     * 取附加的数据
     */
    public Object getExtra() {
        return extra;
    }

    /**
     * 设置附加的数据
     * @param extra 附加数据
     */
    public PagerBaseAdapter<T> setExtra(Object extra) {
        this.extra = extra;
        return this;
    }

    /**
     * 当页面数据改变时，可以调用本函数刷新页面。
     */
    public void refresh() {
        super.notifyDataSetChanged();
    }

    /**
     * 设置页面渲染的事件
     * @param event 事件
     */
    public void setEvent(Event<T> event) {
        this.event = event;
    }

    /**
     * 页面位置类型表，用作{@link Event#getItemPosition(PagerBaseAdapter, Object)} 和 {@link #onGetItemPosition(Object)}事件中的返回值。
     */
    public static class PositionType {
        /**
         * 在使用{@link #refresh()}方法时，ViewPager希望重新确定项目位置，会触发{@link Event#getItemPosition(PagerBaseAdapter, Object)} 和 {@link #onGetItemPosition(Object)}事件，
         * 在这两个事件中返回该值表明当前的项目数据位置没有变化。
         */
        public final static int UNCHANGED = POSITION_UNCHANGED;

        /**
         * 在使用{@link #refresh()}方法时，ViewPager希望重新确定项目位置，会触发{@link Event#getItemPosition(PagerBaseAdapter, Object)} 和 {@link #onGetItemPosition(Object)}事件，
         * 在这两个事件中返回该值表明当前的项目数据已不存在。
         */
        public final static int NONE = POSITION_NONE;
    }

    /**
     * 页面渲染时的接口事件
     */
    public abstract static class Event<E> {
        /**
         * 获取页面数量的事件，在此事件中返回页面的数量。
         *
         * @param adapter 页面适配器对象
         * @return 返回页面的数量。默认返回null，表示不做自定义处理，使用默认的返回值，即当前设置的页面项目数据集合的成员数量。
         */
        public Object getItemCount(PagerBaseAdapter<E> adapter) {
            return null;
        }

        /**
         * 调用{@link #refresh()}刷新项目数据时，获取页面项目的位置。默认为：-1 {@link PositionType#UNCHANGED}，表示页面位置没有变化。
         * 返回：-2 {@link PositionType#NONE}，表示页面项目位置变化。返回>=0的值表示新的项目位置。
         * @param adapter 页面适配器对象
         * @param object 页面的项目数据
         * @return 默认返回null，表示不做自定义处理，返回默认值，即-1 {@link PositionType#UNCHANGED}
         */
        public Object getItemPosition(PagerBaseAdapter<E> adapter, Object object) {
            return null;
        }

        /**
         * 页面开始更新的事件
         * @param adapter 页面适配器对象
         * @param container 页面的视图容器
         * @return 返回true表示忽略默认的处理逻辑，默认返回false
         */
        public boolean startUpdate(PagerBaseAdapter<E> adapter, ViewGroup container) {
            return false;
        }

        /**
         * 实例化页面项目的事件
         *
         * @param adapter 页面适配器对象
         * @param container 页面的视图容器
         * @param position 页面的项目位置
         * @return 返回页面的视图对象，默认返回null，表示不做自定义处理，从设置的页面项目数据集合的对应项目位置获取数据返回。
         */
        public Object instantiateItem(PagerBaseAdapter<E> adapter, ViewGroup container, int position) {
            return null;
        }

        /**
         * 销毁页面项目的事件，在本事件中处理销毁页面项目的逻辑
         *
         * @param adapter 页面适配器对象
         * @param container 页面的视图容器
         * @param position 页面的项目位置
         * @param object 页面的项目数据
         * @return 在本事件中完成页面销毁的逻辑后，返回true表示忽略默认的处理逻辑，否则仍会执行默认的处理逻辑。
         */
        public boolean destroyItem(PagerBaseAdapter<E> adapter, ViewGroup container, int position, Object object) {
            return false;
        }

        /**
         * 页面结束更新的事件
         * @param adapter 页面适配器对象
         * @param container 页面的视图容器
         * @return 返回true表示忽略默认的处理逻辑，默认返回false
         */
        public boolean finishUpdate(PagerBaseAdapter<E> adapter, ViewGroup container) {
            return false;
        }

        /**
         * 判断页面视图是否源自项目对象时的事件
         * @param adapter 页面适配器对象
         * @param view 视图对象
         * @param object 页面的项目数据
         */
        public Object isViewFromObject(PagerBaseAdapter<E> adapter, View view, Object object) {
            return null;
        }

        /**
         * 获取页面的项目数据。根据页面显示的内容返回项目数据。
         * @param adapter 页面适配器对象
         * @param position 项目索引
         * @return  一般返回视图对象或界面碎片(Fragment)，默认返回null，表示不做自定义处理，从设置的项目数据集合中获取对应位置的项目数据返回。
         */
        public Object getItem(PagerBaseAdapter<E> adapter, int position) {
            return null;
        }

        /**
         * 设置主项目的事件
         * @param adapter 页面适配器对象
         * @param container 页面的视图容器
         * @param position 项目索引
         * @param object 项目数据
         * @return 返回true表示忽略默认的处理逻辑，默认返回false
         */
        public boolean setPrimaryItem(PagerBaseAdapter<E> adapter, ViewGroup container, int position, Object object) {
            return false;
        }
    }

    @Override
    public int getCount() {
        Object res;
        if(event != null && ((res = event.getItemCount(this)) instanceof Integer)) {
            return (int) res;
        }
        return getItemCount();
    }

    /**
     * 获取页面的项目数量的事件，在此事件中返回页面的项目数量，默认返回设置的数据集合的成员数量。若未设置数据集合，那么默认返回0
     */
    protected int getItemCount() {
        return itemDataList == null ? 0 : itemDataList.size();
    }

    /**
     * 获取页面的项目数据。根据页面显示的内容返回项目数据。
     * @param position 项目索引
     * @return  一般返回视图对象或界面碎片(Fragment)
     */
    protected Object getItem(int position) {
        Object res;
        if(event != null && ((res = event.getItem(this, position)) != null)) return res;
        return itemDataList == null || itemDataList.size() <= position ? null : itemDataList.get(position);
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        Object res;
        if(event != null && ((res = event.isViewFromObject(this, view, object)) instanceof Boolean)) {
            return (boolean) res;
        }
        return checkIsViewFromObject(view, object);
    }

    /**
     * 判断页面视图是否源自页面的项目数据的事件
     * @param view 页面视图对象
     * @param object 页面的项目数据
     */
    protected boolean checkIsViewFromObject(Object view, Object object) {
        return view == object;
    }

    @Override
    public int getItemPosition(@NonNull Object object) {
        Object res;
        if(event != null && ((res = event.getItemPosition(this, object)) instanceof Integer)) {
            return (int) res;
        }
        return onGetItemPosition(object);
    }

    /**
     * 调用{@link #refresh()}刷新项目数据时，获取页面项目的位置。默认为：-1 {@link PositionType#UNCHANGED}，表示页面位置没有变化。
     * 返回：-2 {@link PositionType#NONE}，表示页面项目位置变化。返回>=0的值表示新的项目位置。
     * @param object 页面的项目数据
     */
    protected int onGetItemPosition(Object object) {
        return super.getItemPosition(object);
    }

    @Override
    public void startUpdate(@NonNull ViewGroup container) {
        if(event != null && (event.startUpdate(this, container))) return;
        onStartUpdate(container);
    }

    /**
     * 页面开始更新事件
     * @param container 页面的视图容器
     */
    protected void onStartUpdate(ViewGroup container) {
        super.startUpdate(container);
    }

    @NonNull @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        Object res;
        if(event != null && ((res = event.instantiateItem(this, container, position)) != null)) return res;
        return onInstantiateItem(container, position);
    }

    /**
     * 实例化页面项目的事件
     * @param container 页面的视图容器
     * @param position 页面的项目位置
     */
    protected Object onInstantiateItem(ViewGroup container, int position) {
        return super.instantiateItem(container, position);
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        if(event != null && (event.destroyItem(this, container, position, object))) return;
        onDestroyItem(container, position, object);
    }

    /**
     * 销毁页面项目的事件，在本事件中处理销毁页面项目的逻辑
     * @param container 页面的视图容器
     * @param position 页面的项目位置
     * @param object 页面的项目数据
     */
    protected void onDestroyItem(ViewGroup container, int position, Object object) {

    }

    @Override
    public void finishUpdate(@NonNull ViewGroup container) {
        if(event != null && (event.finishUpdate(this, container))) return;
        onFinishUpdate(container);
    }

    /**
     * 页面结束更新事件
     * @param container 页面视图容器
     */
    protected void onFinishUpdate(ViewGroup container) {
        super.finishUpdate(container);
    }

    @Override
    public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        if(event != null && (event.setPrimaryItem(this, container, position, object))) return;
        onSetPrimaryItem(container, position, object);
    }

    /**
     * 设置主项目的事件
     * @param container 页面的视图容器
     * @param position 项目索引
     * @param object 项目数据
     */
    protected void onSetPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
    }
}
